﻿package components
{
	import com.adobe.air.logging.FileTarget;
	import com.bit101.components.Component;
	import com.bit101.components.VUISlider;
	import components.FisheyeListBoxItem;
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.Sprite
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.text.TextField;
	import flash.text.TextFieldAutoSize;
	import flash.text.TextFormat;
	import flash.ui.ContextMenuItem;
	
	/**
	 * ...
	 * @author s
	 */
	public class FisheyeListBox extends Component
	{
		private var _items:Vector.<FisheyeListBoxItem>;
		private var _itemHash:Object;
		
		private var _autoScrollStartPos:Number;
		private var _autoScrollEndPos:Number;
		private var _autoScrollMotionCt:int;
		private var _autoScrollMotionMax:int;
		private var _focusedPos:Number;
		private var _lastClickedItem:FisheyeListBoxItem;
		
		private static const ROW_MARGIN:int = 4;
		internal static const TEXT_HEIGHT:int = 24;
		private static const ITEM_HEIGHT:int = TEXT_HEIGHT + ROW_MARGIN;

		private static const TEXT_HIGHLIGHT_COLOR:int = 0x0066FF;
		private static const TEXT_UNHIGHLIGHT_COLOR:int = 0x404040;
		
		// event types
		public static const CLICK_ITEM:String = "click_item";
		
		public function FisheyeListBox(parent:Sprite, x:int, y:int, width:int, height:int) 
		{
			super();
			super.x = x;
			super.y = y;
			super.width = width;
			super.height = height;
			parent.addChild(this);
			
			_focusedPos = 0;
			
			_items = new Vector.<FisheyeListBoxItem>;
			_itemHash = new Object;
			_lastClickedItem = null;
			
			parent.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);  // Componentに対してMOUSE_MOVEイベントが発生しない？のでparentで受ける
			//super.addEventListener(Event.ENTER_FRAME, onEnterFrame);
		}
		
		
		public function update():void 
		{
			for (var i:int = 0; i < _items.length; i++) {
				var top:Number;
				var bottom:Number;
				var scale:Number;
				
				top = fisheyeTranslation((i + (ROW_MARGIN / 2) / ITEM_HEIGHT) / _items.length, _focusedPos, 8, 0, 1.0) * this.height;
				bottom = fisheyeTranslation((i + (ROW_MARGIN / 2 + TEXT_HEIGHT) / ITEM_HEIGHT) / _items.length, _focusedPos, 8, 0, 1.0) * this.height;
				scale = (bottom - top) / TEXT_HEIGHT;
				
				if (scale >= 0.1 || _items[i].textColor == TEXT_HIGHLIGHT_COLOR) {
					_items[i].y = top;
					_items[i].scaleX = scale;
					_items[i].scaleY = scale;
					_items[i].visible = true;
					if (_items[i].textColor == TEXT_HIGHLIGHT_COLOR) {
						_items[i].alpha = 1.0;
					}
					else{
						_items[i].alpha = scale;
					}
				}
				else {
					_items[i].visible = false;
				}
			}
			
			//trace("mouseY=" + mouseY + ", this.height=" + this.height + ", top=" +  debugStr);
		}
		
		
		private function fisheyeTranslation(x:Number, xFocus:Number, d:Number, xLow:Number, xHigh:Number):Number
		{
			var xDiff:Number;
			var xMax:Number;
			
			if (x < xFocus) {
				xDiff = xFocus - x;
				xMax = xFocus - xLow;
				return xFocus - ((d + 1) * xDiff * xMax) / (d * xDiff + xMax);
			}
			else {
				xDiff = x - xFocus;
				xMax = xHigh - xFocus;
				return xFocus + ((d + 1) * xDiff * xMax) / (d * xDiff + xMax);
			}
		}
		
		
		private function createItem(text:String, key:String):FisheyeListBoxItem 
		{
			var item:FisheyeListBoxItem = new FisheyeListBoxItem(this, text, key, TEXT_UNHIGHLIGHT_COLOR);
			item.addEventListener(MouseEvent.CLICK, onClickItem);
			return item;
		}
		
		public function push(text:String, key:String = null):void 
		{
			var item:FisheyeListBoxItem = createItem(text, key);
			item._index = _items.length;
			_items.push(item);
			if (key != null) {
				_itemHash[key] = item;
			}
			update();
		}
		
		public function unshift(text:String, key:String = null):void 
		{
			var item:FisheyeListBoxItem = createItem(text, key);
			
			for (var i:int = 0; i < _items.length; i++) {
				_items[i]._index++;
			}
			item._index = 0;
			
			_items.unshift(item);
			if (key != null) {
				_itemHash[key] = item;
			}
			update();
		}
		
		public function highlightItem(key:String):void 
		{
			if (_itemHash[key] != undefined) {
				var item:FisheyeListBoxItem = _itemHash[key];
				item.alpha = 0.8;
				item.textColor = TEXT_HIGHLIGHT_COLOR;
				item.visible = true;
			}
		}
		
		public function focusItem(key:String):void 
		{
			if (_itemHash[key] != undefined) {
				var item:FisheyeListBoxItem = _itemHash[key];
				_autoScrollStartPos = _focusedPos;
				_autoScrollEndPos = (item._index + 0.5) / _items.length;
				_autoScrollMotionCt = 0;
				_autoScrollMotionMax = 16;
				this.addEventListener(Event.ENTER_FRAME, onEnterFrameForAutoScroll);
			}
		}
		
		public function unhighlightAll():void 
		{
			for (var i:int = 0; i < _items.length; i++) {
				_items[i].textColor = TEXT_UNHIGHLIGHT_COLOR;
			}
		}
		
		public function get lastClickedItem():FisheyeListBoxItem
		{
			return _lastClickedItem;
		}
		
		
		// event listener
		private function onMouseMove(e:Event):void 
		{
			_focusedPos = Number(mouseY) / this.height;
			if (_focusedPos < 0) {
				_focusedPos = 0;
			}
			else if (_focusedPos > 1.0) {
				_focusedPos = 1.0;
			}
			update();
		}
		
		private function onEnterFrameForAutoScroll(e:Event):void 
		{
			var d:Number = 1 - Math.exp(-_autoScrollMotionCt / _autoScrollMotionMax * 10);
			d = Math.pow(d, 4);
			
			if (_autoScrollMotionCt < _autoScrollMotionMax) {
				_focusedPos = _autoScrollStartPos + d * (_autoScrollEndPos - _autoScrollStartPos);
				_autoScrollMotionCt++;
			}
			else {
				_focusedPos = _autoScrollEndPos;
				removeEventListener(Event.ENTER_FRAME, onEnterFrameForAutoScroll);
			}
			update();
		}
		
		private function onClickItem(e:Event):void 
		{
			_lastClickedItem = e.target as FisheyeListBoxItem;
			dispatchEvent(new Event(CLICK_ITEM));
		}
	}

}
